// 数组模板示例和非类型参数

#ifndef _61CLASSTMEPLATEANDNON_TYPEDPARAM_HPP_
#define _61CLASSTMEPLATEANDNON_TYPEDPARAM_HPP_
#include <iostream>
#include <string>

// 1.数组模板示例
// 表达式参数有一些限制,表达式参数可以是整型/枚举/引用或指针。

// 像下面这样就是不合法的
// template <class T,double d>
// 但是这样的是合法的
// template <class T,double * d>

// 另外模板代码不能修改参数值，也不能够使用参数的地址。所以在ArrayTP模板中不能够使用诸如n++等表达式。
// 参数模板表达式的主要缺点是:每种数组大小都将生成自己的模板。

template <typename T, int n>
class ArrayTP
{
private:
    T ar[n];

public:
    ArrayTP() {}
    explicit ArrayTP(const T &v);
    virtual T &operator[](int i);
    virtual T &operator[](int i) const;
};

template <class T, int n>
ArrayTP<T, n>::ArrayTP(const T &v)
{
}

template <class T, int n>
T &ArrayTP<T, n>::operator[](int i)
{
    if (i < 0 || i > n)
    {
        std::cerr << "Error in array limits:" << i << " is out of range\n";
        std::exit(EXIT_FAILURE);
    }
    return ar[i];
}

template <class T, int n>
T &ArrayTP<T, n>::operator[](int i) const
{
    if (i < 0 || i > n)
    {
        std::cerr << "Error in array limits:" << i << " is out of range\n";
        std::exit(EXIT_FAILURE);
    }
    return ar[i];
}

// 递归使用模板
ArrayTP<ArrayTP<int, 5>, 10> twoee;
// 相当于 int twoee [10][5];

// 使用多个类型参数的模板
template <class T, class R>
class Pair
{
private:
    T t;
    R r;

public:
    T &first();
    R &second();
    T first() const { return t; }
    R second() const { return r; }
    Pair(const T &t, const R &r) {}
    ~Pair() {}
};

template <class T, class R>
Pair<T, R>::Pair(const T &t, const R &r) : t(t), r(r) {}

template <class T, class R>
T &Pair<T, R>::first()
{
    return t;
}

template <class T, class R>
R &Pair<T, R>::second()
{
    return r;
}

// 默认类型模板参数
template <class T, class R = int>
class TR_int
{
}

#endif // _61CLASSTMEPLATEANDNON_TYPEDPARAM_HPP_
